package
{
	import flash.utils.*;
	
	import org.flixel.*;
	
	import levels.*;
	import utilities.*;
	import states.*;
	
	/**
	 * ...
	 * @author JAC
	 */
	public final class Registry
	{
		public static var epicBackground:FlxGroup;
		public static var musicVolume:Number;
		public static var soundVolume:Number;
		public static var darknessColor:uint;
		public static var heatMap:HeatMap;
		public static var paused:Boolean;
		public static var levelGraveMap:Dictionary;
		public static var actionMap:Dictionary;
		public static var progress:Class;
		
		// Group layers
		public static var maze:Maze;
		public static var edge:FlxTilemap;
		public static var ui:UI;
		public static var enemies:FlxGroup;
		public static var items:FlxGroup;
		public static var interactions:FlxGroup;
		public static var treasures:FlxGroup;
		public static var player:FlxGroup;
		public static var levelGraves:FlxGroup;
		public static var projectiles:FlxGroup;
		public static var misc:FlxGroup;
		public static var decorations:FlxGroup;
		public static var lights:FlxGroup;
		public static var darkness:FlxSprite;
		public static var animations:FlxGroup;
		
		private static var save:FlxSave;
		
		public static function init():void
		{
			paused = false;
			musicVolume = 0.75;
			soundVolume = 0.75;
			
			initSave();
			
			initEpicBackground();
			
			heatMap = new HeatMap();
			levelGraveMap = new Dictionary();
			
			actionMap = new Dictionary();
			initActionMap();
			
			initLayers();
			
			loadProgress();
		}
		
		public static function get firstLevel():Class
		{
			return Tutorial_1;
		}
		
		public static function addLayers():void
		{
			FlxG.state.add(maze);
			FlxG.state.add(edge);
			FlxG.state.add(decorations);
			FlxG.state.add(interactions);
			FlxG.state.add(items);
			FlxG.state.add(treasures);
			FlxG.state.add(levelGraves);
			FlxG.state.add(misc);
			FlxG.state.add(enemies);
			FlxG.state.add(projectiles);
			FlxG.state.add(player);
			FlxG.state.add(lights);
			FlxG.state.add(darkness);
			FlxG.state.add(ui);
			FlxG.state.add(animations);
			FlxG.state.add(heatMap);
		}
		
		public static function removeLayers():void
		{
			FlxG.state.remove(maze);
			FlxG.state.remove(edge);
			FlxG.state.remove(decorations);
			FlxG.state.remove(interactions);
			FlxG.state.remove(items);
			FlxG.state.remove(treasures);
			FlxG.state.remove(levelGraves);
			FlxG.state.remove(misc);
			FlxG.state.remove(enemies);
			FlxG.state.remove(projectiles);
			FlxG.state.remove(player);
			FlxG.state.remove(lights);
			FlxG.state.remove(darkness);
			FlxG.state.remove(ui);
			FlxG.state.remove(animations);
			FlxG.state.remove(heatMap);
		}
		
		public static function clearLayers():void
		{
			decorations.callAll("destroy");
			decorations.clear();
			enemies.callAll("destroy");
			enemies.clear();
			interactions.callAll("destroy");
			interactions.clear();
			items.callAll("destroy");
			items.clear();
			treasures.callAll("destroy");
			treasures.clear();
			projectiles.callAll("destroy");
			projectiles.clear();
			player.callAll("destroy");
			player.clear();
			misc.callAll("destroy");
			misc.clear();
			animations.clear();
			ui.clearInventory();
			ui.resetText();
			lights.clear();
		}
		
		public static function disableLayers():void
		{
			maze.exists = false;
			edge.exists = false;
			decorations.exists = false;
			interactions.exists = false;
			items.exists = false;
			treasures.exists = false;
			player.exists = false;
			misc.exists = false;
			enemies.exists = false;
			projectiles.exists = false;
			lights.exists = false;
			darkness.exists = false;
			ui.exists = false;
			animations.exists = false;
			heatMap.exists = false;
			levelGraves.exists = false;
		}
		
		public static function saveProgress(currentClass:Class):void
		{
			progress = currentClass;
			save.data.progress = getQualifiedClassName(progress);
			save.flush();
		}
		
		public static function saveVolumes():void
		{
			save.data.musicVolume = musicVolume;
			save.data.soundVolume = soundVolume;
			save.flush();
		}
		
		public static function clearProgress():void
		{
			progress = firstLevel;
			musicVolume = 0.75;
			soundVolume = 0.75;
			FlxG.music.volume = Registry.musicVolume;
			save.data.progress = getQualifiedClassName(progress);
			save.data.musicVolume = musicVolume;
			save.data.soundVolume = soundVolume;
			levelGraves.callAll("destroy");
			levelGraves.clear();
			buildLevels();
		}
		
		public static function get isNewPlayer():Boolean
		{
			return progress == firstLevel;
		}
		
		public static function unlockAllLevels():void
		{
			var lg:LevelGrave = levelGraves.members[0];
			while (lg.next != null)
			{
				lg.setState(LevelGrave.CLEARED);
				lg = lg.next;
			}
			lg.setState(LevelGrave.CLEARED); 
			progress = lg.level;
		}
		
		private static function initSave():void
		{
			save = new FlxSave();
			save.bind("GhostOfTheTombs");
			
			if (save.data.version == null || save.data.version != Main.VERSION)
			{
				save.data.version = new String();
				save.data.version = Main.VERSION;
				save.data.progress = null;
				save.data.musicVolume = null;
				save.data.soundVolume = null;
			}
			
			if (save.data.progress == null)
			{
				save.data.progress = new String();
				save.data.progress = getQualifiedClassName(Tutorial_1);
			}
			
			if (save.data.musicVolume == null)
			{
				save.data.musicVolume = musicVolume;
			}
			
			if (save.data.soundVolume == null)
			{
				save.data.soundVolume = soundVolume;
			}
			
			save.flush();
		}
		
		private static function buildLevels():void
		{
			var lg:LevelGrave;
			
			lg = makeAndAddLevelGrave(3, 10, Tutorial_1, lg, "Intro to Tombs");			//1
			lg.setState(LevelGrave.UNLOCKED);
			lg = makeAndAddLevelGrave(3, 13, Level_1, lg, "Cool and Easy");				//2
			lg = makeAndAddLevelGrave(3, 16, Level_15, lg, "Protect It All");			//3
			lg = makeAndAddLevelGrave(7, 16, Tutorial_2, lg, "Intro to Items");			//4
			lg = makeAndAddLevelGrave(7, 13, Level_2, lg, "Faster!");					//5
			lg = makeAndAddLevelGrave(7, 10, Level_3, lg, "Oh Where Did the Time Go?");	//6
			lg = makeAndAddLevelGrave(11, 10, Tutorial_4, lg, "The Brute Arrives");		//7
			lg = makeAndAddLevelGrave(11, 13, Level_4, lg, "Double Whammy");			//8
			lg = makeAndAddLevelGrave(11, 16, Level_5, lg, "Time Management");			//9
			lg = makeAndAddLevelGrave(15, 16, Tutorial_3, lg, "Exorcist Engagement");	//10
			lg = makeAndAddLevelGrave(15, 13, Level_16, lg, "Crossfire");				//11
			lg = makeAndAddLevelGrave(15, 10, Level_9, lg, "Teleportation Work");		//12
			lg = makeAndAddLevelGrave(19, 10, Level_10, lg, "Harsh Teamwork");			//13
			lg = makeAndAddLevelGrave(19, 13, Level_6, lg, "Face of Death");			//14
			lg = makeAndAddLevelGrave(19, 16, Level_12, lg, "Make Waves");				//15
			lg = makeAndAddLevelGrave(23, 16, Level_11, lg, "J-A-C");					//16
			lg = makeAndAddLevelGrave(23, 13, Level_14, lg, "That is a Long Tunnel");	//17
			lg = makeAndAddLevelGrave(23, 10, Level_13, lg, "More Waves");				//18
			lg = makeAndAddLevelGrave(27, 10, Level_7, lg, "Large Maze"); 				//19
			lg = makeAndAddLevelGrave(27, 13, Level_8, lg, "All Of Them");				//20
		}
		
		private static function unlockLevelsFromProgress():void
		{
			if (levelGraves.length == 0)
			{
				buildLevels();
			}
			
			var lg:LevelGrave = levelGraves.members[0];
			while (lg != null && lg.level != progress)
			{
				lg.setState(LevelGrave.CLEARED);
				lg = lg.next;
			}
			lg.setState(LevelGrave.UNLOCKED);
		}
		
		private static function makeAndAddLevelGrave(i:int, j:int, levelClass:Class, prevLevel:LevelGrave = null, levelName:String = null):LevelGrave
		{
			var lg:LevelGrave = new LevelGrave(i, j);
			
			if (prevLevel != null)
			{
				prevLevel.next = lg;
			}
			
			var className:String = getQualifiedClassName(levelClass).slice(8);
			
			lg.level = levelClass;
			lg.className = className;
			lg.previous = prevLevel;
			lg.name = levelName == null ? className.replace('_', ' ') : levelName;
			
			levelGraves.add(lg);
			levelGraveMap[getQualifiedClassName(levelClass)] = lg;
			
			lg.ID = levelGraves.length;
			lg.addText("ID", lg.ID.toString(), 30, 50);
			
			return lg;
		}
		
		private static function loadProgress():void
		{
			progress = getDefinitionByName(save.data.progress) as Class;
			musicVolume = save.data.musicVolume;
			soundVolume = save.data.soundVolume;
			unlockLevelsFromProgress();
		}
		
		private static function initEpicBackground():void
		{
			epicBackground = new FlxGroup();
			
			var bg:FlxSprite = new FlxSprite();
			bg.loadGraphic(Assets.ImgMenuBG, false, false, FlxG.width, FlxG.height, true);
			
			var eyes:FlxSprite = new FlxSprite();
			eyes.loadGraphic(Assets.ImgMenuEyes, true, false, FlxG.width, FlxG.height, true);
			eyes.addAnimation("looking", [0, 1], 1);
			eyes.play("looking");
			
			var torches:FlxSprite = new FlxSprite();
			torches.loadGraphic(Assets.ImgMenuTorches, true, false, FlxG.width, FlxG.height, true);
			torches.addAnimation("burning", [0, 1, 2, 3], 12);
			torches.play("burning");
			
			epicBackground.add(bg);
			epicBackground.add(eyes);
			epicBackground.add(torches);
		}
		
		private static function initActionMap():void
		{
			actionMap["SpeedBooster"] = 1;
			actionMap["RockThrow"] = 2;
			actionMap["Slow"] = 3;
			actionMap["Teleporter"] = 4;
			actionMap["Trapdoor"] = 5;
		}
		
		private static function initLayers():void
		{
			maze = new Maze();
			initEdge();
			ui = new UI();
			decorations = new FlxGroup();
			
			misc = new FlxGroup();
			lights = new FlxGroup();
			initDarkness();
			animations = new FlxGroup();
			
			projectiles = new FlxGroup;
			enemies = new FlxGroup();
			items = new FlxGroup();
			interactions = new FlxGroup();
			treasures = new FlxGroup();
			player = new FlxGroup();
			player.add(new Player());
			
			levelGraves = new FlxGroup();
		}
		
		private static function initEdge():void
		{
			var edgeData:Array = new Array(33 * 25);
			var i:uint;
			for (i = 0; i < edgeData.length; i++)
			{
				edgeData[i] = 0;
			}
			
			for (i = 0; i < 33; i++)
			{
				edgeData[i] = 1;
				edgeData[24 * 33 + i] = 1;
			}
			
			for (i = 0; i < 25; i++)
			{
				edgeData[i * 33] = 1;
				edgeData[i * 33 + 32] = 1;
			}
			
			var edgeString:String = FlxTilemap.arrayToCSV(edgeData, 33);
			edge = new FlxTilemap();
			edge.loadMap(edgeString, Assets.ImgTileAutoSand, 0, 0, FlxTilemap.AUTO);
			edge.x = -50;
			edge.y = -50;
		}
		
		private static function initDarkness():void
		{
			darknessColor = 0xAA000000;
			darkness = new FlxSprite();
			darkness.makeGraphic(FlxG.width, FlxG.height, darknessColor);
			darkness.blend = "multiply";
		}
	}
}